#include "Artist.h"
#include <iostream>

Artist::Artist(bool& quit)
{
    SDL_Surface* glSurface;

    SDL_Init( SDL_INIT_EVERYTHING );
    TTF_Init();
    SDL_WM_SetCaption( "explore v0.0.3", NULL );
    SDL_ShowCursor(SDL_DISABLE);
    SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
    if ( (glSurface = SDL_SetVideoMode( WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_BPP,  SDL_OPENGL)) == NULL){
		quit=true;
    }

    swScreen = SDL_CreateRGBSurface(SDL_SWSURFACE,WINDOW_WIDTH,WINDOW_HEIGHT,WINDOW_BPP,
    								glSurface->format->Rmask , glSurface->format->Gmask, glSurface->format->Bmask, glSurface->format->Amask);

    SDL_FreeSurface(glSurface);

    init_GL();

    Uint8 *SDL_GetKeyState(int *numkeys);

}

void Artist::showCursor()
{
    SDL_ShowCursor(SDL_ENABLE);
}

void Artist::hideCursor()
{
    SDL_ShowCursor(SDL_DISABLE);
}

Artist::~Artist()
{
	if(swScreen!=NULL)
		SDL_FreeSurface(swScreen);
    if(screenTexture)
    	glDeleteTextures( 1, &screenTexture );
    SDL_Quit();
}

void Artist::init_GL()
{
	glEnable( GL_TEXTURE_2D );

    //inky blue (0,0,16)
	glClearColor( 0.0f, 0.0f, 0.0627f, 0.0f );

	glViewport( 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT );

	glClear( GL_COLOR_BUFFER_BIT );

	glMatrixMode( GL_PROJECTION );
	glLoadIdentity();

	glOrtho(0.f, WINDOW_WIDTH, 0.f, WINDOW_HEIGHT, -1.0f, 1.0f);

	glMatrixMode( GL_MODELVIEW );
	glLoadIdentity();

	// get the number of channels in the SDL screen
	nOfColors = swScreen->format->BytesPerPixel;

	if (nOfColors == 4)     // contains an alpha channel
	{
			if (swScreen->format->Rmask == 0x000000ff)
					texture_format = GL_RGBA;
			else
					texture_format = GL_BGRA;
	} else if (nOfColors == 3)     // no alpha channel
	{
			if (swScreen->format->Rmask == 0x000000ff)
					texture_format = GL_RGB;
			else
					texture_format = GL_BGR;
	} else {
			printf("warning: the screen is not truecolor..  this will probably break\n");
			// this error should not go unhandled
	}

	// Have OpenGL generate a texture object handle for us
	glGenTextures( 1, &screenTexture );

	// Bind the texture object
	glBindTexture( GL_TEXTURE_2D, screenTexture );


	// Set the texture's stretching properties
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
	//end openGL initilization
}

void Artist::displayToGL(float rotation)
{
	glClear(GL_COLOR_BUFFER_BIT);

	// Bind the texture object
	glBindTexture( GL_TEXTURE_2D, screenTexture );

	// Edit the texture object's image data using the information SDL_screen gives us
	glTexImage2D( GL_TEXTURE_2D, 0, nOfColors, swScreen->w, swScreen->h, 0,
					  texture_format, GL_UNSIGNED_BYTE, swScreen->pixels );

	glMatrixMode( GL_MODELVIEW );
	glPushMatrix();
		glLoadIdentity();
		glTranslatef(WINDOW_WIDTH/2, WINDOW_HEIGHT/2, 0.f);
		glRotatef(rotation, 0.0f, 0.0f, 1.0f);
		glTranslatef(-WINDOW_WIDTH/2, -WINDOW_HEIGHT/2, 0.f);
		glBegin( GL_QUADS );
			//Bottom-left vertex (corner)
			glTexCoord2i( 0, 0 );
			glVertex3f( 0.f, WINDOW_HEIGHT, 0.f);

			//Bottom-right vertex (corner)
			glTexCoord2i( 1, 0 );
			glVertex3f( WINDOW_WIDTH, WINDOW_HEIGHT, 0.f);

			//Top-right vertex (corner)
			glTexCoord2i( 1, 1 );
			glVertex3f( WINDOW_WIDTH, 0, 0.f);

			//Top-left vertex (corner)
			glTexCoord2i( 0, 1 );
			glVertex3f( 0, 0, 0.f);
		glEnd();
	glPopMatrix();
}

SDL_Surface* Artist::getScreen()
{
    return swScreen;
}

void Artist::clear()
{
    Uint32 color = 0x000016;
    SDL_FillRect( swScreen, NULL, color);
}

void Artist::drawBox(SDL_Rect* rect, Uint32 color)
{
    SDL_FillRect( swScreen, rect, color);
}

Uint32 Artist::get_pixel32( SDL_Surface *surface, int x, int y )
{
    //Convert the pixels to 32 bit
    Uint32 *pixels = (Uint32 *)surface->pixels;

    //Get the requested pixel
    return pixels[ ( y * surface->w ) + x ];
}

void Artist::put_pixel32( SDL_Surface *surface, int x, int y, Uint32 pixel )
{
    //Convert the pixels to 32 bit
    Uint32 *pixels = (Uint32 *)surface->pixels;

    //Set the pixel
    pixels[ ( y * surface->w ) + x ] = pixel;
}

SDL_Surface* Artist::rotate_surface( SDL_Surface *surface, Direction dir, SDL_Rect framesize)
{
    //Pointer to the soon to be flipped surface
    SDL_Surface *newSurface = NULL;

    //If the image is color keyed
    if( surface->flags & SDL_SRCCOLORKEY )
    {
        newSurface = SDL_CreateRGBSurface( SDL_SWSURFACE, surface->w, surface->h, surface->format->BitsPerPixel, surface->format->Rmask, surface->format->Gmask, surface->format->Bmask, 0 );
    }
    //Otherwise
    else
    {
        newSurface = SDL_CreateRGBSurface( SDL_SWSURFACE, surface->w, surface->h, surface->format->BitsPerPixel, surface->format->Rmask, surface->format->Gmask, surface->format->Bmask, surface->format->Amask );
    }

    //If the surface must be locked
    if( SDL_MUSTLOCK( surface ) )
    {
        //Lock the surface
        SDL_LockSurface( surface );
    }
    if(!framesize.w)
        framesize.w = 32;
    if(!framesize.h)
        framesize.h = 32;

    int rx = 0;
    int ry = 0;

    //Go through frames
    std::cout << "Rotating sprite\nnewSurface w: " << newSurface->w << "\nframesize.w: " << framesize.w << "\ni 0..." << newSurface->w / framesize.w << "\n\n";
    for(int i=0; i< newSurface->w / framesize.w; i++)
    {
        //Go through rows
        for( int y = 0; y < newSurface->h; y++)
        {
            //Go through columns
            for( int x = 0; x < framesize.w; x++)
            {
                //Get pixel
                Uint32 pixel = get_pixel32( surface, x+ i*framesize.w, y );

                if( dir == UP || dir == DOWN )
                {
                    rx = i*framesize.w + (framesize.w - x) - 1;
                    ry = newSurface->h - y - 1;

                }
                else if( dir == RIGHT )
                {
                    rx = i*framesize.w + y;
                    ry = (framesize.w - x) - 1;
                }
                else if( dir == LEFT )
                {
                    rx = i*framesize.w + newSurface->h - y - 1;
                    ry = x;
                }
                put_pixel32( newSurface, rx, ry, pixel );
            }
        }
    }
    //Unlock surface
    if( SDL_MUSTLOCK( surface ) )
    {
        SDL_UnlockSurface( surface );
    }

    //Copy color key
    if( surface->flags & SDL_SRCCOLORKEY )
    {
        SDL_SetColorKey( newSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY, surface->format->colorkey );
    }

    SDL_FreeSurface(surface);

    //Return newSurface surface
    return newSurface;
}

SDL_Surface* Artist::flip_surface( SDL_Surface *surface, int flags )
{
    //Pointer to the soon to be flipped surface
    SDL_Surface *flipped = NULL;

    //If the image is color keyed
    if( surface->flags & SDL_SRCCOLORKEY )
    {
        flipped = SDL_CreateRGBSurface( SDL_SWSURFACE, surface->w, surface->h, surface->format->BitsPerPixel, surface->format->Rmask, surface->format->Gmask, surface->format->Bmask, 0 );
    }
    //Otherwise
    else
    {
        flipped = SDL_CreateRGBSurface( SDL_SWSURFACE, surface->w, surface->h, surface->format->BitsPerPixel, surface->format->Rmask, surface->format->Gmask, surface->format->Bmask, surface->format->Amask );
    }

    //If the surface must be locked
    if( SDL_MUSTLOCK( surface ) )
    {
        //Lock the surface
        SDL_LockSurface( surface );
    }

    //Go through columns
    for( int x = 0, rx = flipped->w - 1; x < flipped->w; x++, rx-- )
    {
        //Go through rows
        for( int y = 0, ry = flipped->h - 1; y < flipped->h; y++, ry-- )
        {
            //Get pixel
            Uint32 pixel = get_pixel32( surface, x, y );

            //Copy pixel
            if( ( flags & FLIP_VERTICAL ) && ( flags & FLIP_HORIZONTAL ) )
            {
                put_pixel32( flipped, rx, ry, pixel );
            }
            else if( flags & FLIP_HORIZONTAL )
            {
                put_pixel32( flipped, rx, y, pixel );
            }
            else if( flags & FLIP_VERTICAL )
            {
                put_pixel32( flipped, x, ry, pixel );
            }
        }
    }

    //Unlock surface
    if( SDL_MUSTLOCK( surface ) )
    {
        SDL_UnlockSurface( surface );
    }

    //Copy color key
    if( surface->flags & SDL_SRCCOLORKEY )
    {
        SDL_SetColorKey( flipped, SDL_RLEACCEL | SDL_SRCCOLORKEY, surface->format->colorkey );
    }

    //Return flipped surface
    return flipped;
}

void Artist::flip(Direction dir)
{
    float rot;
    //the direction gravity moves objects
    switch(dir)
    {
        case DOWN: rot = 0.0f; break;
        case UP: rot = 180.0f; break;
        case LEFT: rot = 90.0f; break;
        case RIGHT: rot = 270.0f; break;
    }
    displayToGL(rot);
	//Update screen
    SDL_GL_SwapBuffers();
}

void Artist::framerate_limit(bool menu)
{
    int fps = (menu ? MENU_FRAMES_PER_SECOND : FRAMES_PER_SECOND);

    static int lastTime = 0;
	int timeSpent = SDL_GetTicks() - lastTime;
    if( timeSpent < 1000 / fps )
        SDL_Delay( ( 1000 / fps ) - timeSpent);
}

SDL_Surface* Artist::load_image(std::string filename, Uint8 r, Uint8 g, Uint8 b){
    //The image that's loaded
    SDL_Surface* loadedImage = NULL;

    SDL_Surface* optimizedImage = NULL;

    //Load the image
    loadedImage = IMG_Load( filename.c_str() );

    //If the image loaded
    if( loadedImage != NULL )
    {
        //Create an optimized surface
        optimizedImage = SDL_DisplayFormat( loadedImage );

        //Free the old surface
        SDL_FreeSurface( loadedImage );

        //If the surface was optimized
        if( optimizedImage != NULL )
        {
            //Color key surface
            SDL_SetColorKey( optimizedImage, SDL_SRCCOLORKEY, SDL_MapRGB( optimizedImage->format, r, g, b ) );
        }
    }
    else
    {
        //aw crap
    }
    return optimizedImage;
}

SDL_Surface* Artist::load_semitransp( std::string filename){
    SDL_Surface* loadedImage = NULL;
    loadedImage = IMG_Load( filename.c_str() );
    return loadedImage;
}
